/* Copyright (c) Soon.Liao 2024. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * Create Date : 2024
 * @Date: 2024-10-14 07:57:06
 * @LastEditors: soon.liao
 * @LastEditTime: 2024-10-26 14:08:18
 * @FilePath: /src/application/ws63/rgb_master/paj7620u2/paj7620u2.c
 * @Description: NA
 * NA
 */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <securec.h>

#include "i2c.h"
#include "gpio.h"
#include "pinctrl.h"
#include "soc_osal.h"
#include "hal_gpio.h"
#include "app_init.h"

#include "paj7620u2.h"
#include "cmd_json.h"

#define PAJ7620U2_DATA_OFFSET 8
#define PAJ7620U2_ENTRY_TIME 800 // 等待I2C初始化完成时间ms
#define PAJ7620U2_QUIT_TIME 300  // 每次查询时间间隔单位ms

// I2C settings
#define PAJ7620U2_MASTER_ADDR 0x0
#define PAJ76620U2_I2C_IDX 1
#define PAJ76620U2_I2C_BAUDRATE (400 * 1000) // 400k
#define PAJ76620U2_I2C_MASTER_PIN_MODE 2
#define PAJ76620U2_I2C_SDA 15 // Paj76620 i2c data GPIO15/SDA/TXD1
#define PAJ76620U2_I2C_SCL 16 // Paj76620 i2c clock GPIO16/SCL/RXD1

#define PAJ76620U2_INT 10 // Paj76620 int GPIO10/A12

#define PAJ76620U2_TASK_STACK_SIZE 0x2000
#define PAJ76620U2_TASK_PRIO 17

static uint32_t paj7620u2_read(uint8_t *buffer, uint32_t buffLen)
{
    i2c_data_t data = {0};
    data.receive_buf = buffer;
    data.receive_len = buffLen;
    uint32_t retval = uapi_i2c_master_read(PAJ76620U2_I2C_IDX, PAJ_7620_U2_I2C_ADDRESS, &data);
    if (retval != 0) {
        osal_printk("\r\nPAJ7620U2_Read() failed, %0X!\r\n", retval);
        return retval;
    }
    return 0;
}

static uint32_t paj7620u2_write(uint8_t *buffer, uint32_t buffLen)
{
    uint16_t dev_addr = PAJ_7620_U2_I2C_ADDRESS;
    i2c_data_t data = {0};
    data.send_buf = buffer;
    data.send_len = buffLen;
    uint32_t retval = uapi_i2c_master_write(PAJ76620U2_I2C_IDX, dev_addr, &data);
    if (retval != 0) {
        osal_printk("nPAJ7620U2_Write(%02X) failed, %0X!\n", data.send_buf[1], retval);
        return retval;
    }
    return 0;
}

/******************* PAJ7620U2 Driver Interface *****************************/
uint8_t I2C_readByte(int reg)
{
    uint32_t retval = 0;
    uint8_t addr_buff[] = {reg};
    uint8_t buffer[] = {0x00};
    retval = paj7620u2_write(addr_buff, sizeof(addr_buff));
    if (retval != 0) {
        return retval;
    }
    retval = paj7620u2_read(buffer, sizeof(buffer));
    if (retval != 0) {
        return retval;
    }
    return buffer[0];
}

uint16_t I2C_readU16(int reg)
{
    int ret;
    uint16_t readU16data = 0x00;

    uint8_t addr_buf[] = {reg};
    uint8_t read_buf[2];
    uint8_t len = 2;
    ret = paj7620u2_write(addr_buf, sizeof(addr_buf));
    if (ret != 0) {
        return ret;
    }
    ret = paj7620u2_read(read_buf, len);
    if (ret != 0) {
        osal_printk("\r\nPAJ7620U2 I2C_readU16 0x%X,0x%X ret=%d\r\n", read_buf[0], read_buf[1], ret);
        return ret;
    }
    readU16data = ((uint16_t)((read_buf[1] << PAJ7620U2_DATA_OFFSET) + read_buf[0]));
    return readU16data;
}

void i2c_write_byte(int reg, int val)
{
    uint32_t retval = 0;
    uint8_t dataSend[2] = {reg, val};
    retval = paj7620u2_write(dataSend, sizeof(dataSend));
    if (retval != 0) {
        osal_printk("\r\nI2C_writeByte(reg=0x%02x,val=0x%02X) failed, 0x%0X!\r\n", reg, val, retval);
        return;
    }
    return;
}

void on_paj7620u2_event(pin_t pin, uintptr_t param)
{
    unused(pin);
    unused(param);
    uint16_t Gesture_Data;
    osal_msleep(PAJ7620U2_QUIT_TIME);
    Gesture_Data = I2C_readU16(PAJ_INT_FLAG1);
    if (Gesture_Data) {
        osal_printk("\r\nGesture Sensor Gesture_Data=0x%x\r\n ", Gesture_Data);
        switch (Gesture_Data) {
            case PAJ_UP:
                osal_printk("\r\nUp\r\n");
                create_json_paj7620u2_cammand(STR_UP);
                break;

            case PAJ_DOWN:
                osal_printk("\r\nDown\r\n");
                create_json_paj7620u2_cammand(STR_DOWN);
                break;

            case PAJ_LEFT:
                osal_printk("\r\nLeft\r\n");
                create_json_paj7620u2_cammand(STR_LEFT);
                break;

            case PAJ_RIGHT:
                osal_printk("\r\nRight\r\n");
                create_json_paj7620u2_cammand(STR_RIGHT);
                break;

            case PAJ_FORWARD:
                osal_printk("\r\nForward\r\n");
                create_json_paj7620u2_cammand(STR_FORWARD);
                break;

            case PAJ_BACKWARD:
                osal_printk("\r\nBackward\r\n");
                create_json_paj7620u2_cammand(STR_BACKWARD);
                break;

            case PAJ_CLOCKWISE:
                osal_printk("\r\nClockwise\r\n");
                create_json_paj7620u2_cammand(STR_CLOCKWISE);
                break;

            case PAJ_COUNT_CLOCKWISE:
                osal_printk("\r\nAntiClockwise\r\n");
                create_json_paj7620u2_cammand(STR_COUNT_CLOCKWISE);
                break;

            case PAJ_WAVE:
                osal_printk("\r\nWave\r\n");
                create_json_paj7620u2_cammand(STR_WAVE);
                break;

            default:
                break;
        }
        Gesture_Data = 0;
    }
}

void paj7620u2_interrupt_mode_init(void)
{
    uapi_pin_set_mode(PAJ76620U2_INT, HAL_PIO_FUNC_GPIO);
    gpio_select_core(PAJ76620U2_INT, CORES_APPS_CORE);
    uapi_gpio_set_dir(PAJ76620U2_INT, GPIO_DIRECTION_INPUT);
    uapi_gpio_register_isr_func(PAJ76620U2_INT, GPIO_INTERRUPT_FALLING_EDGE, on_paj7620u2_event);
}

uint8_t paj7620u2_init(void)
{
    unsigned char i, state;

    osal_msleep(PAJ7620U2_ENTRY_TIME); // wait I2C init
    paj7620u2_interrupt_mode_init();

    state = I2C_readByte(0x00); // Read state
    osal_printk("\r\nGesture Sensor state =0x%x\r\n", state);
    if (state != 0x20) {
        return 0; // Wake up failed
    }
    i2c_write_byte(PAJ_BANK_SELECT, 0); // Select Bank 0
    for (i = 0; i < INIT_ARRAY; i++) {
        i2c_write_byte(g_init_register_array[i][0], g_init_register_array[i][1]); // Power up initialize
    }
    i2c_write_byte(PAJ_BANK_SELECT, 0);
    return 1;
}

int paj7620u2_task(void)
{
    uint8_t i;

    osal_printk("\r\n Gesture Sensor Program paj7620u2_task init start...\r\n");

    if (!paj7620u2_init()) {
        osal_printk("\r\n Gesture Sensor Error\r\n");
        return 0;
    }

    i2c_write_byte(PAJ_BANK_SELECT, 0); // Select Bank 0
    for (i = 0; i < GESTURE_ARRAY_SIZE; i++) {
        i2c_write_byte(INIT_GESTURE_ARRAY[i][0], INIT_GESTURE_ARRAY[i][1]); // Gesture register initializes
    }
    osal_printk("\r\n Gesture Sensor OK\r\n");

    return 0;
}

void paj7620u2_entry(void)
{
    uint32_t ret;
    osal_task *taskid;
    // 创建任务调度
    osal_kthread_lock();
    // 创建任务1
    taskid =
        osal_kthread_create((osal_kthread_handler)paj7620u2_task, NULL, "paj7620u2_task", PAJ76620U2_TASK_STACK_SIZE);
    ret = osal_kthread_set_priority(taskid, PAJ76620U2_TASK_PRIO);
    if (ret != OSAL_SUCCESS) {
        osal_printk("create paj7620u2_task failed .\n");
    }
    osal_kthread_unlock();
}

app_run(paj7620u2_entry);